/*
 * Principal.c
 *      Author: Grupo Klow
 */

#define FIN_LINEA 	'\n'
#define FIN_CADENA 	'\0'
#define ESP_BLANCO 	' '

#define TAMANIO_BLOQUE 		1024

//ERRORES
#define EXITO 				0
#define ERROR_ARGS_INSUF	1
#define ERROR_FORMATO		2
#define ERROR_ORD_INDEF		3
//
#include <string.h>
#include <stdlib.h>

#include "../../Logger/src/Logger.h"

/******* DEFINICION DE FUNCIONES AUXILIARES DE INTERFAZ *******/
void mostrarError(int codigo);
void opcionHelp();
unsigned int opcionInsertar(char* cadena, Logger * logger);
unsigned int opcionBuscar(char* cadenaBuscada, Logger * logger, FILE * salida);
void opcionVolcar(char * nombreArchivo, Logger * logger);
void opcionOPruebasDefault(Logger * logger);

char* leerEntrada ();
char* obtenerArgumento (char* lista, unsigned int * posicion);
int obtenerDatos(char * cadena, int * clave, char ** valor);
/******* FIN DEFINICION DE FUNCIONES AUXILIARES DE INTERFAZ *******/


//FORMATO ENTRADA
//NOMBRE ARCHIVO -COMANDO ARG1 ARG2 ARGN
//Argv[0] es el path donde se esta ejecutando

int main( int argc, char** argv )
{

	char * nombreArchivoMaestro = NULL; // Archio donde se encuentra la estructura principal
	char * opcion = NULL;	// Opcion seleccionada
	char * entrada = NULL;
	char * actual;

	//unsigned int posicion = 0;
	FILE * salida;

	unsigned int codigoError=0;
	unsigned int posicion=0;

	//No ingreso ningun parametro
	if (argc == 1) {
		mostrarError(ERROR_ARGS_INSUF);
		return 1;
	}

	//Esta consultando la ayuda?
	if (strcmp(argv[1],"-h")==0) {
		opcionHelp();
		return EXIT_SUCCESS;
	}

	//Sino quiere consultar la ayuda debe tener al menos 3 parametros.
	//No ingreso ningun parametro
	if (argc < 3) {
		mostrarError(ERROR_ARGS_INSUF);
		return 1;
	}

	nombreArchivoMaestro = argv[1];
	opcion = argv[2];

	Logger logger;
	Logger_Iniciar(&logger, nombreArchivoMaestro,TAMANIO_BLOQUE);

	if (strcmp(opcion,"-I") == 0) {
		//Insertar
		entrada = leerEntrada();

		actual = obtenerArgumento(entrada, &posicion);

		while(actual != NULL && codigoError == 0) {
			codigoError = opcionInsertar(actual,&logger);
			free(actual);
			actual = obtenerArgumento(entrada, &posicion);
		}

		free(entrada);
	} else if (strcmp(opcion,"-B") == 0) {
		//Buscar
		if (argc==4) {
			salida = fopen(argv[3],"w");
		} else {
			salida = stdout;
		}

		entrada = leerEntrada();

		actual = obtenerArgumento(entrada, &posicion);

		while(actual != NULL && codigoError == 0) {
			codigoError = opcionBuscar(actual,&logger,salida);
			free(actual);
			actual = obtenerArgumento(entrada, &posicion);
		}

		free(entrada);

		if (salida != stdout) fclose(salida);
	} else if (strcmp(opcion,"-S") == 0) {
		//Volcar
		if (argc < 4) {
			codigoError = ERROR_ARGS_INSUF;
		} else {
			opcionVolcar(argv[3],&logger);
		}

	} else if (strcmp(opcion,"-D") == 0) {
		//Muestra informacion del logger
		if (argc==4) {
			salida = fopen(argv[4],"w");
		} else {
			salida = stdout;
		}

		Logger_MostrarInfo(&logger,salida);

		if (salida != stdout) fclose(salida);

	} else {
		codigoError = ERROR_ORD_INDEF;

	}
	if(codigoError!=0) {
		mostrarError(codigoError);
	}

	Logger_Cerrar(&logger);

	return EXIT_SUCCESS;
}

void opcionHelp(){
	printf ("Estas ordenes de consola se encuentran definidas internamente.\n\n");
	printf ("archivo -I                      Insertar un elemento.\n");

	printf ("archivo -B                      Busca lineas que contengan el texto ingresado. Muestra los resultados en consola.\n");
	printf ("          archivoDestino        Vuelca los resultados de la busqueda en archivoDestino.\n");
	printf ("                                Formato [A'numeroArchivo'L'numeroLinea'] 'linea con coincidencia'\n");

	printf ("archivo -D                      Muestra informacion del logger.\n");

	printf ("archivo -S                      Vuelca la estructura en pantalla.\n");

	printf ("-h                              Imprime la ayuda.\n");
}

void mostrarError(int codigo)
{
	switch(codigo){
		case ERROR_ARGS_INSUF:
		printf ("ERROR: Cantidad de argumentos insuficientes.\n");
		break;
	case ERROR_FORMATO:
		printf ("ERROR: Formato no correspondiente.\n");
		break;
	case ERROR_ORD_INDEF:
		printf ("ERROR: orden no encontrada.\n");
		break;
	default:
		printf ("ERROR: La operacion no ha podido ser procesada.\n");
		break;
	}
	printf ("Puede consultar la ayuda a traves del comando -h.\n");
}

char* leerEntrada () //Levanta todo el contenido de stdin
{
    char * argumentos = (char*) malloc (sizeof(char) * 2);
    char c = fgetc(stdin); //lee desde entrada standard

    memset(argumentos,0,2);

	int i = 0;

	while (c != EOF)
	{
		argumentos[i] = c;
		argumentos = (char *) realloc (argumentos, strlen(argumentos) +2);
		i++;
		c = fgetc(stdin);
		argumentos[i+1] = '\0';
	}

    return argumentos;
}

char* obtenerArgumento(char* entrada, unsigned int * posicion) {

	char * inicioBusqueda;

	char * inicio = NULL;
	char * fin = NULL;
	char * retorno;

	unsigned int longitud = 0;

	if (*posicion > strlen(entrada)) return NULL;

	inicioBusqueda = *posicion * sizeof(char) + entrada;

    inicio = strchr(inicioBusqueda,'(');

    if (inicio == NULL ) return NULL;

    fin = strchr(inicio,')');

    if (fin == NULL) return NULL;

    longitud = fin - inicio + 1;

    retorno = (char *) malloc(sizeof(char) * longitud);

    memcpy(retorno,inicio,longitud);

    (*posicion)= fin - entrada + 1;

    return retorno;
}

int obtenerDatos(char * cadena, int * clave, char ** valor) {
	char * inicio = NULL;
	char * fin = NULL;
	char * medio = NULL;

	char * aux;

	int longitudClave = 0;
	int longitudValor = 0;

	inicio = strchr(cadena,'(');
	medio = strchr(cadena,';');
	fin = strchr(cadena,')');

	if (inicio == NULL || medio == NULL || fin == NULL) return 0;

	longitudClave = medio - inicio;
	longitudValor = fin - medio;

	aux = (char *) malloc(sizeof(char) * longitudClave);
	aux[0] = '\0';
	strncat(aux, (inicio + sizeof(char)),longitudClave - 1);

	(*clave) = atoi(aux);
	free(aux);

	if (longitudValor > 1) {
		(*valor) = (char *) malloc(sizeof(char) * longitudValor);
		(*valor)[0] = '\0';
		strncat(*valor, (medio + sizeof(char)), longitudValor - 1);
	} else {
		(*valor)=NULL;
	}

	return 1;
}

unsigned int opcionInsertar(char* cadena, Logger * logger) {

	int clave = 0;
	char* valor;

	if (obtenerDatos(cadena,&clave, &valor) && valor !=NULL) {
		Logger_Insertar(logger,valor); //
		printf("Linea agregada.\n");
		free(valor);
		return EXITO;
	} else {
		return ERROR_FORMATO;
	}

}

void opcionVolcar(char * nombreArchivo, Logger * logger) {

	Logger_Volcar(logger,nombreArchivo);

	printf("Volcado completado.\n");
}

unsigned int opcionBuscar(char* cadena, Logger * logger, FILE * salida) {
	int clave = 0;
	char* valor;

	if (obtenerDatos(cadena,&clave, &valor)) {

		unsigned int cantidadResultados = Logger_Buscar(logger,valor,salida);

		if (cantidadResultados == 0) {
			printf("No se han concentrado coincidencias dentro del archivo con a cadena '%s'.\n",valor);
		} else {
			printf("%i resultados encontrados con la cadena '%s'.\n",cantidadResultados,valor);
		}

		free(valor);

		return EXITO;
	} else {
		return ERROR_ORD_INDEF;
	}
}
